AWS CDK のカスタムリソースを使って単一のアカウントで Inspector を有効化してみた
こんにちは、製造ビジネステクノロジー部の若槻です。
Amazon Inspector は、EC2 インスタンスや ECR コンテナイメージ、Lambda 関数をスキャンして、ソフトウェア脆弱性やネットワーク露出などのセキュリティ問題を自動検出するサービスです。
この Inspector を使う場合は明示的に有効化操作を行う必要がありますが、対応する CloudFormation リソースが無いため、有効化操作を IaC 化したい場合はカスタムリソースを使うことになります。
今回は、カスタムリソースを使って単一アカウントの Inspector を有効化する構成を AWS CDK で実装してみました。
なお、本記事での「Inspector」は Inspector v2 を指している前提とします。
やってみた
CDK コード
Inspector をカスタムリソースで有効化する CDK コードです。
import { Construct } from 'constructs';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as cr from 'aws-cdk-lib/custom-resources';
export class InspectorConstruct extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
new cr.AwsCustomResource(
this,
'InspectorV2Enabler',
{
/**
* Inspector2 の enable API を呼び出して Inspector2 を有効化する
* @see https://docs.aws.amazon.com/inspector/v2/APIReference/API_Enable.html
*/
onCreate: {
service: 'Inspector2',
action: 'enable',
parameters: {
resourceTypes: ['EC2', 'ECR', 'LAMBDA', 'LAMBDA_CODE'],
},
physicalResourceId: cr.PhysicalResourceId.of('InspectorV2Enabler'),
},
policy: cr.AwsCustomResourcePolicy.fromStatements([
new iam.PolicyStatement({
actions: [
'inspector2:Enable',
/**
* アカウントに対して Inspector が使用するサービスリンクロールを作成するための権限
* @see https://docs.aws.amazon.com/ja_jp/inspector/latest/user/using-service-linked-roles.html
* @see https://docs.aws.amazon.com/ja_jp/inspector/latest/user/slr-permissions-agentless.html
*/
'iam:CreateServiceLinkedRole',
],
resources: ['*'],
}),
]),
/**
* カスタムリソースから inspector2 の disable API を呼び出しても
* Inspector2 が無効化されない挙動となったため、onDelete による設定無効化は実装していない。
* 無効化したい場合は手動で実施する。
* @see https://docs.aws.amazon.com/inspector/v2/APIReference/API_Disable.html
*/
}
);
}
}
動作確認
Inspector の有効化状況を確認します。この時点では無効化されています。
$ aws inspector2 batch-get-account-status --account-ids ${AWS_ACCOUNT_ID}
{
"accounts": [
{
"accountId": "XXXXXXXXXXXX",
"resourceState": {
"ec2": {
"status": "DISABLED"
},
"ecr": {
"status": "DISABLED"
},
"lambda": {
"status": "DISABLED"
},
"lambdaCode": {
"status": "DISABLED"
}
},
"state": {
"status": "DISABLED"
}
}
],
"failedAccounts": []
}
サービスリンクロール AWSServiceRoleForAmazonInspector2
および AWSServiceRoleForAmazonInspector2Agentless
はこの時点で作成されていません。これらのロールは Inspector 有効化時に存在していなければ自動作成されます。
$ aws iam get-role --role-name AWSServiceRoleForAmazonInspector2
An error occurred (NoSuchEntity) when calling the GetRole operation: The role with name AWSServiceRoleForAmazonInspector2 cannot be found.
$ aws iam get-role --role-name AWSServiceRoleForAmazonInspector2Agentless
An error occurred (NoSuchEntity) when calling the GetRole operation: The role with name AWSServiceRoleForAmazonInspector2Agentless cannot be found.
前述の CDK コードを使用してカスタムリソースを作成するデプロイを行います。デプロイが正常に完了したらに設定状況を確認します。
Inspector が有効化されています。
$ aws inspector2 batch-get-account-status --account-ids ${AWS_ACCOUNT_ID}
{
"accounts": [
{
"accountId": "XXXXXXXXXXXX",
"resourceState": {
"ec2": {
"status": "ENABLED"
},
"ecr": {
"status": "ENABLED"
},
"lambda": {
"status": "ENABLED"
},
"lambdaCode": {
"status": "ENABLED"
}
},
"state": {
"status": "ENABLED"
}
}
],
"failedAccounts": []
}
サービスリンクロールも作成されています。
$ aws iam get-role --role-name AWSServiceRoleForAmazonInspector2
{
"Role": {
"Path": "/aws-service-role/inspector2.amazonaws.com/",
"RoleName": "AWSServiceRoleForAmazonInspector2",
"RoleId": "AROAUL6WVPY2FUAOM2SNU",
"Arn": "arn:aws:iam::XXXXXXXXXXXX:role/aws-service-role/inspector2.amazonaws.com/AWSServiceRoleForAmazonInspector2",
"CreateDate": "2025-01-12T06:35:08+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "inspector2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Description": "Allowing Inspector to call AWS services on behalf of customers",
"MaxSessionDuration": 3600,
"RoleLastUsed": {}
}
}
$ aws iam get-role --role-name AWSServiceRoleForAmazonInspector2Agentless
{
"Role": {
"Path": "/aws-service-role/agentless.inspector2.amazonaws.com/",
"RoleName": "AWSServiceRoleForAmazonInspector2Agentless",
"RoleId": "AROAUL6WVPY2O2WBCZJ7Y",
"Arn": "arn:aws:iam::XXXXXXXXXXXX:role/aws-service-role/agentless.inspector2.amazonaws.com/AWSServiceRoleForAmazonInspector2Agentless",
"CreateDate": "2025-01-12T06:35:08+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "agentless.inspector2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Description": "Allowing Inspector to call AWS services on behalf of customers",
"MaxSessionDuration": 3600,
"RoleLastUsed": {}
}
}
補足
カスタムリソースから Inspector の無効化はできない?
当初 Inspector の無効化も可能な下記の CDK コードを試しましたが、onDelete を実装しても Inspector が無効化されませんでした。
import { Construct } from 'constructs';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as cr from 'aws-cdk-lib/custom-resources';
export class InspectorConstruct extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
new cr.AwsCustomResource(this, 'InspectorV2Enabler', {
onCreate: {
service: 'Inspector2',
action: 'enable',
parameters: {
resourceTypes: ['EC2', 'ECR', 'LAMBDA', 'LAMBDA_CODE'],
},
physicalResourceId: cr.PhysicalResourceId.of('InspectorV2Enabler'),
},
// カスタムリソースから Inspector の無効化はできなかった
onDelete: {
service: 'Inspector2',
action: 'disable',
physicalResourceId: cr.PhysicalResourceId.of('InspectorV2Enabler'),
},
policy: cr.AwsCustomResourcePolicy.fromStatements([
new iam.PolicyStatement({
actions: [
'inspector2:Enable',
'inspector2:Disable',
'iam:CreateServiceLinkedRole',
],
resources: ['*'],
}),
]),
});
}
}
一応 parameters
でアカウント ID を指定してみましたが、挙動は変わらず。
parameters: {
accountIds: [cdk.Aws.ACCOUNT_ID],
},
policy
権限不足ではないのかデプロイ自体は失敗しません。また手動で無効化は可能でした。環境起因の可能性もありますが、もう少し詳細な調査が必要そうです。もちろん無効化まで IaC 化する必要の無い場合もあるかと思うので、運用要件と照らし合わせて検討する必要があります。
Inspector 無効化前にサービスリンクロールは削除できない
当然ですが Inspector が有効化されている間はサービスリンクロールが必須となるので、Inspector 無効化前に削除することはできません。試すとエラーとなります。
複数アカウント環境での Inspector 有効化
AWS Organizations などで複数アカウントを管理しているなどでデプロイ実行環境と異なるアカウントの Inspector を有効化したい場合は enable API の accountIds
パラメーターを指定する必要があります。
今回はデプロイ実行環境の単一アカウントのみを対象としているため、accountIds
パラメーターは指定していません。
おわりに
カスタムリソースを使って単一アカウントの Inspector を有効化する構成を AWS CDK で実装してみました。
セキュリティサービスの利用は設定系が多いため、CloudFormtion および CDK での IaC 化に際してはカスタムリソースの利用が宿命となります。留意するようにしましょう。
以上